#include <stdio.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>  // sockaddr_in 结构体类型

#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include <pthread.h>
#include <sys/types.h>

void *recv_task(void *arg){  // 接收消息的任务函数
    int sock_fd = *((int *)arg);
    // 开始接收数据
    char buf[1024] = "";
    char send_ip[16] = ""; // 存IP
    while(1){
        bzero(buf, 1024);
        bzero(send_ip, 16);

        struct sockaddr_in send_addr;  // 定义接收到的网络数据包的来源地址信息
        bzero(&send_addr, sizeof(send_addr));
        socklen_t slen = sizeof(send_addr);

        ssize_t datalen= recvfrom(sock_fd, buf, 1024,  0, (struct sockaddr *)&send_addr, &slen);
        if(datalen > 0){
            // 显示数据来源(IP, port) 和数据
            inet_ntop(AF_INET, &send_addr.sin_addr.s_addr, send_ip, 16);
            printf("%s(%d) -> %s\n", send_ip, ntohs(send_addr.sin_port),  buf);
        }
    }
}

// ./demo7 <port>
int main(int argc, char const *argv[])
{
    if(argc < 2) return -1;

    char *dest_ip = "10.35.161.255";  // 发送目标主机的IP是网段的广播地址
    uint16_t dest_port = atoi(argv[1]); // 发送目标主机的端口号
   

    // 1. 创建UDP套接字
    int sock_fd = socket(AF_INET, SOCK_DGRAM, 0); 
    if(sock_fd < 0) {
        perror("socket udp");
        return -1;
    }


    // 2. 定义本地绑定的地址
    struct  sockaddr_in bind_addr;
    bind_addr.sin_family = AF_INET; // IPv4
    bind_addr.sin_port =  htons( dest_port );  // 端口号转成大端字节序
    bind_addr.sin_addr.s_addr = INADDR_ANY;  // INADDR_ANY 类似 0.0.0.0 (主机的任意的IP)

    bind(sock_fd, (struct sockaddr *)&bind_addr, sizeof(bind_addr));

      // 设置socket套接字支持广播
    int optval = 1;
    setsockopt(sock_fd, SOL_SOCKET, SO_BROADCAST, &optval, 4);


    // 通过线程接收本地网卡的数据
    pthread_t tid;
    pthread_create(&tid, NULL, recv_task, &sock_fd);

    // 3. 定义目标主机的地址（IP、端口号，IP类型）
    struct  sockaddr_in send_addr;
    send_addr.sin_family = AF_INET; // IPv4
    send_addr.sin_port =  htons( dest_port );  // 端口号转成大端字节序
    send_addr.sin_addr.s_addr = inet_addr(dest_ip); 

    
    //3. 开始发送数据
    char buf[1024] = "";
    while(1){
        bzero(buf, 1024);
        printf("=> ");
        fgets(buf, 1024, stdin);
        buf[strlen(buf)-1] = 0; // 去\n

        ssize_t slen=sendto(sock_fd, buf, strlen(buf), 0, 
                    (struct sockaddr *)&send_addr, sizeof(send_addr));

        if(strncmp("exit", buf, 4) == 0) break;
    }
    // 取消接收网络数据线程
    pthread_cancel(tid);
    pthread_join(tid, NULL);

    close(sock_fd);  // 4. 通信结束，关闭socket套接字
    return 0;
}

